﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Globalization;
using System.Xml.Serialization;
using System.IO;
using System.Xml;

namespace ExtEasy
{
    public static class ClassExtensions
    {
        /// <summary>
        /// По названию параметра загружает его значение из query string. 
        /// В случае успешного выполнения операции возвращает true.
        /// </summary>
        /// <typeparam name="T">Тип считываемого параметра.</typeparam>
        /// <param name="paramname">Имя считываемого параметра.</param>
        /// <param name="value">Значение считываемого параметра.</param>
        /// <returns>Возвращает True если параметр существует в query string и его значение корректно преобразуется к типу T.</returns>
        public static bool ReadFromQuery<T>(this string paramname, out T value)
        {
            try
            {
                // value = default(T) ;
                if (string.IsNullOrEmpty(paramname)) throw new Exception("Param name is null or empty!");
                if (HttpContext.Current == null) throw new Exception("Param name is null or empty!");                

                string paramValue = HttpContext.Current.Request.Params[paramname];
                if (paramValue == null) throw new Exception("Param name is null or empty!");

                value = paramValue.Cast<T>();
                return true;
            }
            // catch (InvalidCastException)
            catch (Exception ex)
            {
                value = default(T);
                string msg = ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Преобразует string к типу Т 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="paramValue"></param>
        /// <returns></returns>
        public static T Cast<T>(this string paramValue)
        {
            return (T)Convert.ChangeType(paramValue, typeof(T), CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Возвращает окончание слова 
        /// </summary>
        /// <param name="s1">окончание ед.ч. ("мероприятие")</param>
        /// <param name="s2">окончание мн.ч. ("мероприятия")</param>
        /// <param name="s3">окончание очень мн.ч. ("мероприятий")</param>       
        /// <returns></returns>
        public static string GetWordEnds(this int count, string s1, string s2, string s3)
        {
            if (Convert.ToInt32(count / 10) % 10 == 1) return s3;
            if (count % 10 == 1) return s1;
            if ((count % 10 == 2) || (count % 10 == 3) || (count % 10 == 4))  return s2;            
            return s3;

            //return (Convert.ToInt32(count / 10) % 10 == 1) ? s3 : (count % 10 == 1 ? s1 : (((count % 10 == 2) || (count % 10 == 3) || (count % 10 == 4)) ? s2 : s3));
        }

        /// <summary>
        /// Получает MD5 по строке
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string GetMD5Hash(this string input)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
            bs = x.ComputeHash(bs);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string password = s.ToString();
            return password;
        }
        
        /// <summary>
        /// Преобразует массив в строку с разделителем sep
        /// </summary>
        /// <param name="arr">Массив</param>
        /// <param name="sep">Разделитель</param>
        /// <returns></returns>
        public static string ToCommaString(this object[] arr, string sep)
        {
            string res = string.Empty;
            for (int i = 0; i < arr.Length; i++)
            {
                res += arr[i].ToString();
                if (i < arr.Length - 1) res += sep;
            }
            return res;
        }

        /// <summary>
        /// Преобразует строку в List объектов типа Т
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <param name="sep"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this string str, char sep)
        {
            return str.Split(sep).ToList().ConvertAll<T>(Cast<T>);
        }
            
        /// <summary>
        /// Сериализует объект в строку
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string SerializeClass(this object obj)
        {
            using (StringWriter writer = new StringWriter())
            {
                System.Type type = obj.GetType();
                XmlSerializer xs = new XmlSerializer(type);
                xs.Serialize(writer, obj);
                return writer.ToString();
            }
        }

        /// <summary>
        /// Десериализует строку в объект типа Т
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static T DeserializeClass<T>(this string xml) where T : class
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            StringReader read = new StringReader(xml);
            XmlReader reader = new XmlTextReader(read);
            return xs.Deserialize(reader) as T;
        }

        /// <summary>
        /// Создает новый экземпляр объекта путем сериализации и десериализации
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T Clone<T>(this T obj) where T : class, new()
        {
            T w = obj.SerializeClass().DeserializeClass<T>();
            return w;
        }

        
    }
}
